package app.server.project.main.service.service.lv;

import app.server.project.core.constants.Def;
import app.server.project.core.constants.TcpCmd;
import app.server.project.core.exception.SysError;
import app.server.project.core.util.AssertUtil;
import app.server.project.core.websocket.WSMgr;
import app.server.project.main.service.bo.event.ClickEvent;
import app.server.project.main.service.bo.event.LvEvent;
import app.server.project.main.service.db.dao.cfg.LvCfgDao;
import app.server.project.main.service.db.dao.user.UserInfoDao;
import app.server.project.main.service.db.entity.cfg.LvCfgEntity;
import app.server.project.main.service.db.entity.user.UserInfoEntity;
import app.server.project.main.service.dto.lv.LvDto;
import lombok.AllArgsConstructor;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;

import java.util.Comparator;

@Service
@AllArgsConstructor
public class UserLvService {

    private UserInfoDao userInfoDao;
    private LvCfgDao lvCfgDao;
    private ApplicationEventPublisher publisher;


    private void pushLv(UserInfoEntity userInfoEntity) {
        WSMgr.push(userInfoEntity.getUserId(), TcpCmd.Lv, LvDto.of(userInfoEntity));
    }


    /**
     * 提升等级,通过改变点击变化
     *
     * @param lv
     * @return
     */
    public long getLvClickNum(int lv, long userId) {
        if (Def.Zero == lv) {
            return Def.Zero;
        }
        var lvDto = this.getDto(userId);
        AssertUtil.isTrue(lv > lvDto.getLv(), SysError.Sys);
        //检查最大等级
        var maxLv = this.lvCfgDao.getAll().stream().max(Comparator.comparingInt(LvCfgEntity::getLv)).get();
        if (lv >= maxLv.getLv()) {
            return maxLv.getClickNum() - lvDto.getClickNum();
        } else {
            var cfg = this.lvCfgDao.getAll().stream().filter(v -> v.getLv() == lv).findFirst();
            return cfg.get().getClickNum() - lvDto.getClickNum();
        }
    }


    /**
     * 检查并且初始化等级
     *
     * @param userId
     */
    public void chkAndInitLv(long userId) {
        UserInfoEntity userInfoEntity = this.userInfoDao.getUserInfoById(userId);
        if (userInfoEntity.getLv() != Def.Zero) return;
        LvCfgEntity first = this.lvCfgDao.getAll().get(Def.Zero);
        userInfoEntity.setLv(first.getLv());
        userInfoEntity.setStartClickNum(Def.Zero);
        userInfoEntity.setEndClickNum(first.getClickNum());
    }

    public LvDto getDto(long userId) {
        this.chkAndInitLv(userId);
        UserInfoEntity userInfoEntity = this.userInfoDao.getUserInfoById(userId);
        return LvDto.of(userInfoEntity);
    }

    /**
     * 订阅次数变化事件
     *
     * @param event
     */
    @EventListener(ClickEvent.class)
    public void onClickEvent(ClickEvent event) {
        UserInfoEntity userInfoEntity = this.userInfoDao.getUserInfoById(event.getUserId());
        this.chkAndInitLv(event.getUserId());
        userInfoEntity.addClickNum(event.getNum());
        //获取目前等级
        int currentLv = userInfoEntity.getLv();
        //检查是否达到最大
        var cfgList = this.lvCfgDao.getAll();
        LvCfgEntity max = cfgList.get(cfgList.size() - 1);
        if (userInfoEntity.getClickNum() > max.getClickNum()) {
            userInfoEntity.setLv(max.getLv());
            userInfoEntity.setStartClickNum(max.getClickNum());
            userInfoEntity.setEndClickNum(max.getClickNum());
        } else {
            for (int i = 0; i < cfgList.size(); i++) {
                LvCfgEntity tempLv = cfgList.get(i);
                if (tempLv.getClickNum() >= userInfoEntity.getClickNum()) {
                    //设置当前等级
                    userInfoEntity.setLv(tempLv.getLv());
                    userInfoEntity.setEndClickNum(tempLv.getClickNum());
                    if (Def.Zero != i) {
                        userInfoEntity.setStartClickNum(this.lvCfgDao.getAll().get(i - 1).getClickNum());
                    }
                    break;
                }
            }
        }
        //等级变化,发送变化等级事件
        this.pushLv(userInfoEntity);
        int nowLv = userInfoEntity.getLv();
        if ((nowLv - currentLv) > 0) {
            this.publisher.publishEvent(LvEvent.of(event.getUserId(), nowLv - currentLv));
        }
    }
}
